/**
 * 
 */
package com.williamoneil.charts.client.widget;

import java.util.List;

import com.google.gwt.canvas.dom.client.Context2d;
import com.google.gwt.canvas.dom.client.Context2d.TextAlign;
import com.google.gwt.canvas.dom.client.Context2d.TextBaseline;
import com.google.gwt.event.dom.client.TouchEvent;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.PopupPanel;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.williamoneil.charts.client.data.ChartBoundsRect;
import com.williamoneil.charts.client.data.ChartElementsData;
import com.williamoneil.charts.client.data.DateAxis;
import com.williamoneil.charts.client.data.PriceAxis;
import com.williamoneil.charts.client.data.Tick;
import com.williamoneil.charts.client.util.CalendarUtil;
import com.williamoneil.charts.client.util.ChartUtil;
import com.williamoneil.charts.client.util.ColorEntityType;
import com.williamoneil.charts.client.util.Colors;
import com.williamoneil.charts.shared.TradeDateType;

/**
 * @author gudipati
 *
 */
public class TrackPricePanel extends PopupPanel {

	private ChartElementsData chartElements = null;
	private ChartBoundsRect chartBounds = null;
	
	private VerticalPanel panel = new VerticalPanel();
	
	private Label dateLabel = new Label(); 
	
	private static final int OFFSET = 20;
	
	private static TrackPricePanel _instance = null;
	
	private TrackPricePanel() {
		// set to auto hide
		super(true);
		super.setAnimationEnabled(true);
		
		super.setWidget(panel);
		
		_instance = this;
	}
	
	public static final TrackPricePanel getInstance(ChartBoundsRect bounds, ChartElementsData chartElements) {
		if(_instance == null) {
			_instance = new TrackPricePanel();
		}
		_instance.setData(bounds, chartElements);
		
		return _instance;
	}
	
	private void setData(ChartBoundsRect bounds, ChartElementsData chartElements) {
		this.chartBounds = bounds;
		this.chartElements = chartElements;
	}
	
	protected void showAt(final int x0, final int y0, final Context2d context, final ChartLayer chartLayer) {
		if(chartElements == null || chartElements.getTicks() == null) {
			return;
		}
		
		panel.clear();
		
		final DateAxis dateAxis = chartElements.getDateAxis();
		final PriceAxis priceAxis = chartElements.getPriceAxis();
		
		final Tick selectedNode = dateAxis.getTickAtX(x0);
		if(selectedNode == null) {
			return;
		}
		
		final int tickSpacing = chartLayer.getTickSpacing(); 
		
		// reverse lookup so that we snap the track price to the pixel
		final int x = dateAxis.getX(selectedNode.getDate());
		final int y = y0;
		
		final int index = dateAxis.getTickIndex(selectedNode.getDate());
		
		final String dtStr = CalendarUtil.toString(selectedNode.getDate());
		dateLabel.setText("Date " + dtStr);
		
		panel.add(dateLabel);
		
		final List<Tick> ticks = chartElements.getTicks();
		
		if(selectedNode.getTradeDateType() == TradeDateType.TRADE_DATE) {
			// get the price % change information
			Tick previousTradedNode = null;
			int previousNodeIndex = index;
			for(int i=1;i<3;i++) {
				previousNodeIndex++;
				if(previousNodeIndex == ticks.size()) {
					break;
				}
				final Tick aData = ticks.get(previousNodeIndex);
				if(aData.getTradeDateType() == TradeDateType.TRADE_DATE) {
					previousTradedNode = aData;
					break;
				}
			}
			
			panel.add(new Label("Open " + selectedNode.getPrice().getOpen().doubleValue()));
			panel.add(new Label("High " + selectedNode.getPrice().getHigh().doubleValue()));
			panel.add(new Label("Low " + selectedNode.getPrice().getLow().doubleValue()));
			panel.add(new Label("Close " + selectedNode.getPrice().getClose().doubleValue()));
			double pctChg = 0;
			if(previousTradedNode != null) {
				pctChg = 100 * (selectedNode.getPrice().getClose().doubleValue() - previousTradedNode.getPrice().getClose().doubleValue()) / previousTradedNode.getPrice().getClose().doubleValue();
				pctChg = ((long) (pctChg * 100)) / 100;
				panel.add(new Label("% Change " + pctChg + "%"));
			}
			panel.add(new Label("Volume " + selectedNode.getVolume().getVolume()));			
		
	
			final int highY = priceAxis.getY(selectedNode.getPrice().getHigh().doubleValue(), chartBounds);
			final int lowY = priceAxis.getY(selectedNode.getPrice().getLow().doubleValue(), chartBounds);	
			
			// draw track price elements
			context.setStrokeStyle(Colors.getColorTheme().getColor(ColorEntityType.TRACKPRICE_LINE));
			context.beginPath();
			// draw cross-lines first

			// below draws y-track-price line but does not draw over the tick
			ChartUtil.lineTo(context, x-(tickSpacing/2)-1, chartBounds.getY(), x-(tickSpacing/2)-1, highY-5);
			ChartUtil.lineTo(context, x-(tickSpacing/2)-1, lowY+5, x-(tickSpacing/2)-1, chartBounds.getHeightWithoutScale());
			
			ChartUtil.lineTo(context, chartBounds.getX(), y, chartBounds.getWidthWithoutScale(), y);
			
			context.stroke();
			
			// draw the price-indicator
			final String priceIndicatorTextColor = Colors.getColorTheme().getColor(ColorEntityType.TRACKPRICE_PRICE_PRICE_INDICATOR_TEXT);
			final String priceIndicatorFillColor = Colors.getColorTheme().getColor(ColorEntityType.TRACKPRICE_PRICE_PRICE_INDICATOR_FILL);
			
			context.beginPath();
			showPriceIndicator(context, priceAxis.getPrice(y, chartBounds), chartBounds, y, priceIndicatorTextColor, priceIndicatorFillColor);
			
			//also highlight the selected tick
			context.beginPath();
			String tickColor = null;

			final double priceChgOpenToClose = selectedNode.getPrice().getOpen().doubleValue() - selectedNode.getPrice().getClose().doubleValue();
				if(priceChgOpenToClose > 0) {
					tickColor = Colors.getColorTheme().getColor(ColorEntityType.TICK_HIGHLIGHTED_UP);
					context.setStrokeStyle(tickColor);
					context.setFillStyle(tickColor);
					
					chartLayer.getPriceVolumeLayer().drawUpTick(context, selectedNode, chartBounds, priceAxis, dateAxis);
				} else if (priceChgOpenToClose < 0) {
					tickColor = Colors.getColorTheme().getColor(ColorEntityType.TICK_HIGHLIGHTED_DOWN);
					context.setStrokeStyle(tickColor);
					context.setFillStyle(tickColor);
					
					chartLayer.getPriceVolumeLayer().drawDownTick(context, selectedNode, chartBounds, priceAxis, dateAxis);
				} else {
					tickColor = Colors.getColorTheme().getColor(ColorEntityType.TICK_NEUTRAL);
					context.setStrokeStyle(tickColor);
					context.setFillStyle(tickColor);				
					
					chartLayer.getPriceVolumeLayer().drawEqualTick(context, selectedNode, chartBounds, priceAxis, dateAxis);
				}
				context.stroke();
		} else {
			context.setStrokeStyle(Colors.getColorTheme().getColor(ColorEntityType.TRACKPRICE_LINE));
			context.beginPath();
			// draw cross-lines 
			ChartUtil.lineTo(context, x-(tickSpacing/2)-1, chartBounds.getY(), x-(tickSpacing/2)-1, chartBounds.getHeightWithoutScale());
			ChartUtil.lineTo(context, chartBounds.getX(), y, chartBounds.getWidthWithoutScale(), y);

			context.stroke();
		}
				
		super.setPopupPositionAndShow(new PositionCallback() {
			@Override
			public void setPosition(int offsetWidth, int offsetHeight) {
				int popupY = 0;
				int popupX = 0;
				if(TouchEvent.isSupported()) {
					// for mobile always show on the top (of the finger touch)
					popupY = chartBounds.getAbsoluteTop() + y - offsetHeight - OFFSET;
					
					popupX = chartBounds.getAbsoluteLeft() + x - offsetWidth - OFFSET;
					if(popupX < 0) {
						popupX = chartBounds.getAbsoluteLeft() + x + OFFSET; 
					}
				} else {
					popupY = chartBounds.getAbsoluteTop() + y + OFFSET;
					if(popupY + offsetHeight > chartBounds.getTotalHeight()) {
						popupY = chartBounds.getAbsoluteTop() + y - offsetHeight - OFFSET; 
					}
					
					popupX = chartBounds.getAbsoluteLeft() + x + OFFSET;
					if(popupX + offsetWidth > chartBounds.getTotalWidth()) {
						popupX = chartBounds.getAbsoluteLeft() + x - offsetWidth - OFFSET; 
					}
				}
				_instance.setPopupPosition(popupX, popupY);
			}
		});
	}
	
	private final static int INDICATOR_HEIGHT = 20;
	private static void showPriceIndicator(final Context2d context, final double price, final ChartBoundsRect bounds, final int y, final String textColor, final String fillColor) {
		final int startX = bounds.getWidthWithoutScale();
		context.setFillStyle(fillColor);
		context.moveTo(startX, y);
		context.lineTo(startX + INDICATOR_HEIGHT/2, y - INDICATOR_HEIGHT/2);
		context.lineTo(startX + INDICATOR_HEIGHT/2, y + INDICATOR_HEIGHT/2);
		context.fill();
		context.fillRect(startX + INDICATOR_HEIGHT/2, y- INDICATOR_HEIGHT/2, bounds.getXScaleLabelWidth() - INDICATOR_HEIGHT/2, INDICATOR_HEIGHT);
		
		final double finalPrice = Math.floor(price *100)/100; 
		context.setFillStyle(textColor);
		context.setFont("10pt Calibri");
		context.setTextAlign(TextAlign.LEFT);
		context.setTextBaseline(TextBaseline.MIDDLE);
		context.fillText("$" + finalPrice, startX + INDICATOR_HEIGHT/2 + 2, y);
	}
}